﻿using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.RateLimiting;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using Sgr;
using Sgr.AspNetCore;
using Sgr.AspNetCore.ActionFilters.AuditLogs;
using Sgr.AspNetCore.Middlewares.AuditLogs;
using Sgr.AspNetCore.Middlewares.ExceptionHandling;
using Sgr.AuditLogs;
using Sgr.AuditLogs.Contributor;
using Sgr.Caching;
using Sgr.Caching.Services;
using Sgr.ExceptionHandling;
using Sgr.Exceptions;
using Sgr.Generator.Segment;
using Sgr.Modules;
using Sgr.Security;
using Sgr.Security.AuthorizationHandlers;
using Sgr.Utilities;
using System;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.RateLimiting;

namespace Microsoft.Extensions.DependencyInjection
{
    /// <summary>
    /// 扩展
    /// </summary>
    public static class ServiceCollectionExtensions
    {
        public static IServiceCollection AddSgrMvcCore(this IServiceCollection services, IHostEnvironment environment, Action<IServiceCollection>? configure = null)
        {
            services.AddSgrCore();

            AddSgrCaching(services);
            AddUserIdentity(services);
            AddModules(services, environment);
            AddSgrRateLimiter(services);

            configure?.Invoke(services);

            return services;
        }

        /// <summary>
        /// 添加RateLimiter
        /// </summary>
        /// <param name="services"></param>
        /// <returns></returns>
        public static IServiceCollection AddSgrRateLimiter(this IServiceCollection services)
        {
            services.AddRateLimiter(options =>
            {
                options.AddFixedWindowLimiter("limiter-fixed-default", opt =>
                {
                    opt.PermitLimit = 10;                           // 每窗口最多 10 次请求
                    opt.Window = TimeSpan.FromMinutes(1);           // 窗口为 1 分钟
                });
                //string strPermitLimit = EnvironmentHelper.GetEnvironmentVariable("SGR_PERMIT_LIMIT") ?? "5";
            });

            return services;
        }

        /// <summary>
        /// 添加缓存服务
        /// </summary>
        /// <param name="services"></param>
        /// <returns></returns>
        public static IServiceCollection AddSgrCaching(this IServiceCollection services)
        {
            services.AddOptions<CacheOptions>()
                .BindConfiguration("Sgr:Caching");

            services.AddMemoryCache();

            if (services.Any(f => f.ServiceType == typeof(ICacheManager)))
                services.Replace(ServiceDescriptor.Singleton<ICacheManager, MemoryCacheManager>());
            else
                services.AddSingleton<ICacheManager, MemoryCacheManager>();

            return services;
        }

        /// <summary>
        /// 添加用户身份相关服务
        /// </summary>
        /// <param name="services"></param>
        /// <returns></returns>
        public static IServiceCollection AddUserIdentity(this IServiceCollection services)
        {
            services.TryAddSingleton<ICurrentUser, DefaultCurrentUser>();

            services.TryAddSingleton<IFunctionPermissionGrantingService, NoFunctionPermissionGrantingService>();
            services.TryAddEnumerable(ServiceDescriptor.Singleton<IAuthorizationHandler, FunctionPermissionHandler>());

            return services;
        }

        /// <summary>
        /// 添加模块化支持
        /// </summary>
        /// <param name="services"></param>
        /// <param name="environment"></param>
        /// <param name="moduleInfoProvider"></param>
        /// <returns></returns>
        public static IServiceCollection AddModules(
            this IServiceCollection services,
            IHostEnvironment environment,
            IModuleInfoProvider? moduleInfoProvider = null)
        {
            //IModuleInfoProvider provider = moduleInfoProvider ?? new AppConfigurationModuleInfoProvider();
            if (!services.Any(sd => sd.ServiceType == typeof(IApplicationInfoContext)))
            {
                ModularApplicationInfoContext applicationInfoContext;
                try
                {
                    applicationInfoContext = new ModularApplicationInfoContext(environment, moduleInfoProvider ?? new AppConfigurationModuleInfoProvider());
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"创建 ModularApplicationInfoContext 失败: {ex.Message}");
                    throw;
                }

                services.AddSingleton<IApplicationInfoContext>(applicationInfoContext);

                foreach (var module in applicationInfoContext.Application.Modules)
                {
                    if (module.Assembly == null)
                        continue;

                    //builder.Services.AddControllers()
                    //    .AddApplicationPart(Assembly.Load(new AssemblyName(AssemblyName)));
                    //services.AddControllers().AddApplicationPart(module.Assembly);

                    Type? moduleStartupType = null;
                    try
                    {
                        Type[] types;
                        try
                        {
                            types = module.Assembly.GetTypes();
                        }
                        catch (ReflectionTypeLoadException ex)
                        {
                            Console.WriteLine($"读取程序集类型时部分失败，模块：{module.Id} ，{ex.Message}");
                            types = Array.Empty<Type>();
                        }

                        moduleStartupType = types
                            .Where(t => t.IsClass && !t.IsAbstract && typeof(IModuleStartup).IsAssignableFrom(t))
                            .FirstOrDefault();
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine($"扫描模块类型时发生错误，模块：{module.Id}，错误：{ex.Message}");
                        moduleStartupType = null;
                    }

                    if (moduleStartupType == null)
                        continue;

                    try
                    {
                        if (Activator.CreateInstance(moduleStartupType) is IModuleStartup moduleStartup)
                        {
                            try
                            {
                                moduleStartup.ConfigureServices(services);
                            }
                            catch (Exception ex)
                            {
                                Console.WriteLine($"模块 {module.Id} ConfigureServices 失败: {ex.Message}");
                            }

                            services.AddSingleton(typeof(IModuleStartup), moduleStartup);
                        }
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine($"模块 {module.Id} ModuleStartup 实例化失败: {ex.Message}");
                    }
                }
            }

            return services;
        }

        /// <summary>
        /// 添加异常
        /// </summary>
        /// <param name="services"></param>
        /// <returns></returns>
        public static IServiceCollection AddSgrExceptionHandling(this IServiceCollection services)
        {
            services.TryAddTransient<ExceptionHandlingMiddleware>();

            services.TryAddSingleton<IExceptionToErrorInfo, DefaultExceptionToErrorInfo>();
            services.TryAddSingleton<IExceptionHandlingOptions, ExceptionHandlingOptions>();

            services.TryAddEnumerable(ServiceDescriptor.Singleton<IExceptionHandler, ValidationExceptionHandler>());

            return services;
        }

        /// <summary>
        /// 添加审计日志相关服务
        /// </summary>
        /// <param name="services"></param>
        /// <param name="isAuditFull"></param>
        /// <returns></returns>
        public static IServiceCollection AddSgrAuditLog(this IServiceCollection services, bool isAuditFull)
        {
            services.TryAddSingleton<IEnableBufferingOptions, EnableBufferingOptions>();

            services.TryAddSingleton<IAuditLogMiddlewareOptions, AuditLogMiddlewareOptions>();
            services.TryAddSingleton<IAuditLogFilterOptions, AuditLogFilterOptions>();

            services.TryAddSingleton<IHttpUserAgentProvider, DefaultHttpUserAgentProvider>();
            if (isAuditFull)
                services.TryAddSingleton<IAuditLogContributor, AuditLogContributorFull>();
            else
                services.TryAddSingleton<IAuditLogContributor, AuditLogContributor>();

            services.TryAddTransient<AuditLogMiddleware>();

            //services.TryAddTransient<AuditLogActionFilterAttribute>();
            //services.TryAddTransient<AuditLogPageFilterAttribute>();
            //services.TryAddTransient<UnAuditLogActionFilterAttribute>();
            //services.TryAddTransient<UnAuditLogPageFilterAttribute>();

            return services;
        }
    }
}